package com.tang.crm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tang.crm.dto.RoleDto;
import com.tang.crm.entity.Permission;
import com.tang.crm.entity.Role;
import com.tang.crm.mapper.ModuleMapper;
import com.tang.crm.mapper.PermissionMapper;
import com.tang.crm.mapper.RoleMapper;
import com.tang.crm.service.PermissionService;
import com.tang.crm.service.RoleService;
import com.tang.crm.utils.AssertUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private ModuleMapper moduleMapper;

    @Autowired
    private PermissionService permissionService;

    /**
     * 查询所有的权限
     * @return
     */
    @Override
    public List<Map<String, Object>> selectRoleList(Integer userId) {
        return roleMapper.selectRoleList(userId);
    }

    /**
     * 分页条件查询角色列表
     * @param roleDto
     * @return
     */
    @Override
    public Map<String, Object> selectByParams(RoleDto roleDto) {
        Map<String, Object> map = new HashMap<>();
        Page<Role> pageInfo = new Page<>(roleDto.getPage(), roleDto.getLimit());
        IPage<Map<String, Object>> mapIPage = roleMapper.selectByParams(pageInfo, roleDto);
        map.put("code", 0);
        map.put("msg", "");
        map.put("count", mapIPage.getTotal());
        map.put("data", mapIPage.getRecords());
        return map;
    }

    /**
     * 添加角色
     *  1. 参数校验
     *      角色名称        非空，名称唯一
     *  2. 设置参数的默认值
     *      是否有效
     *      创建时间
     *      修改时间
     *  3. 执行添加操作，判断受影响的行数
     * @param role
     */
    @Override
    public void addRole(Role role) {
        /* 参数校验 */
        // 角色名称 非空
        AssertUtil.isTrue(StringUtils.isBlank(role.getRoleName()), "角色名称不能为空");
        // 角色名称 名称唯一
        LambdaQueryWrapper<Role> lambdaQueryWrapper =  new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Role::getRoleName, role.getRoleName());
        Role roleData = roleMapper.selectOne(lambdaQueryWrapper);
        AssertUtil.isTrue(roleData != null, "角色名称已存在，请重新输入");
        /* 设置参数的默认值 */
        // 是否有效
        role.setIsValid(1);
        // 创建时间
        role.setCreateDate(new Date());
        // 修改时间
        role.setUpdateDate(new Date());
        /* 执行添加操作，判断受影响的行数 */
        AssertUtil.isTrue(roleMapper.insert(role) != 1, "添加失败");
    }

    /**
     * 修改角色
     *  1. 参数校验
     *      角色ID    非空，且数据存在
     *      角色名称   非空，名称唯一
     *  2. 设置参数的默认值
     *      修改时间
     *  3. 执行更新操作，判断受影响的行数
     * @param role
     */
    @Override
    public void updateRole(Role role) {
        /* 参数校验 */
        // 角色ID 非空，且数据存在
        AssertUtil.isTrue(role.getId() == null, "待更新记录不存在");
        // 角色名称 非空
        AssertUtil.isTrue(StringUtils.isBlank(role.getRoleName()), "角色名称不能为空");
        // 角色名称 名称唯一
        LambdaQueryWrapper<Role> lambdaQueryWrapper =  new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Role::getRoleName, role.getRoleName());
        Role roleData = roleMapper.selectOne(lambdaQueryWrapper);
        // 如果角色不存在，表示可以使用；如果角色存在，查询的ID与当前更新的ID不一致，表示角色名称不一样
        AssertUtil.isTrue(roleData != null && !(roleData.getId().equals(role.getId())), "角色名称已存在，请重新输入");
        /* 设置参数的默认值 */
        // 修改更新时间
        role.setUpdateDate(new Date());
        /* 执行更新操作，判断受影响的行数 */
        AssertUtil.isTrue(roleMapper.updateById(role) != 1, "更新数据失败");
    }

    /**
     * 删除角色
     *  1. 参数校验
     *      角色ID    非空，数据存在
     *  2. 执行删除操作，判断受影响的行数
     * @param roleId
     */
    @Override
    public void deleteRole(Integer roleId) {
        /* 参数校验 */
        // 角色ID 非空
        AssertUtil.isTrue(roleId == null, "待删除的角色信息不存在");
        // 角色ID 数据存在
        Role role = roleMapper.selectById(roleId);
        AssertUtil.isTrue(role == null, "待删除的角色信息不存在");
        /* 执行删除操作，判断受影响的行数 */
        AssertUtil.isTrue(roleMapper.deleteById(roleId) != 1, "删除角色信息失败");
    }

    /**
     * 角色授权
     *
     *  将对应的角色ID与资源ID，添加到对应的权限表中
     *      直接添加权限：不合适，会出现重复的权限数据（执行修改权限操作后删除权限操作时）
     *      推荐使用：
     *          先将已有的权限记录删除，再将需要设置的权限记录添加
     *          1. 通过角色ID查询对应的权限记录
     *          2. 如果权限记录存在，则删除对应的角色拥有的权限记录
     *          3. 如果有权限记录，则添加权限记录 (批量添加)
     * @param roleId
     * @param mIds
     */
    @Override
    @Transactional
    public void addGrant(Integer roleId, Integer[] mIds) {
        // 1. 通过角色ID查询对应的权限记录
        Integer count = permissionMapper.countPermissionByRoleId(roleId);
        // 2. 如果权限记录存在，则删除对应的角色拥有的权限记录
        if (count > 0){
            // 删除权限记录
            LambdaQueryWrapper<Permission> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Permission::getRoleId, roleId);
            permissionMapper.delete(lambdaQueryWrapper);
        }
        // 如果有权限记录
        if (mIds != null && mIds.length > 0){
            List<Permission> permissionList = new ArrayList<>();
            for (Integer mId : mIds) {
                Permission permission = new Permission();
                permission.setRoleId(roleId);
                permission.setModuleId(mId);
                permission.setCreateDate(new Date());
                permission.setUpdateDate(new Date());
                permission.setAclValue(moduleMapper.selectById(mId).getOptValue());
                // 将元素添加到集合中
                permissionList.add(permission);
            }
            // 执行批量添加操作，判断受影响的行数
            AssertUtil.isTrue(!permissionService.saveBatch(permissionList), "添加权限失败");
        }
    }


}
